package simpledb.tx.concurrency;

import simpledb.file.Block;
import java.util.*;

/**
 * The concurrency manager for the transaction. Each transaction has its own
 * concurrency manager. The concurrency manager keeps track of which locks the
 * transaction currently has, and interacts with the global lock table as
 * needed. <br>
 * 
 * 事务的并发管理器。 每个事务都有自己的并发管理器。 并发管理器跟踪事务当前具有的锁，并且根据需要与全局锁表交互。
 * 
 * @author Edward Sciore
 */
public class ConcurrencyMgr {

  /**
   * The global lock table. This variable is static because all transactions
   * share the same table.<br>
   * 全局锁表。 此变量是静态的，因为所有事务共享同一个表。
   */
  private static LockTable locktbl = new LockTable();
  private Map<Block, String> locks = new HashMap<Block, String>();

  /**
   * Obtains an SLock on the block, if necessary. The method will ask the lock
   * table for an SLock if the transaction currently has no locks on that block.
   * <br>
   * 如果需要，获取块上的SLock。 如果事务当前在该块上没有锁，该方法将请求锁表的SLock。
   * 
   * @param blk a reference to the disk block
   */
  public void sLock(Block blk) {
    if (locks.get(blk) == null) {
      locktbl.sLock(blk);
      locks.put(blk, "S");
    }
  }

  /**
   * Obtains an XLock on the block, if necessary. If the transaction does not
   * have an XLock on that block, then the method first gets an SLock on that
   * block (if necessary), and then upgrades it to an XLock. <br>
   * 如果需要，在块上获取XLock。 如果事务在该块上没有XLock，那么该方法首先获取该块上的SLock（如果需要），然后将其升级到XLock。
   * 
   * @param blk a refrence to the disk block
   */
  public void xLock(Block blk) {
    if (!hasXLock(blk)) {
      sLock(blk);
      locktbl.xLock(blk);
      locks.put(blk, "X");
    }
  }

  /**
   * Releases all locks by asking the lock table to unlock each one. <br>
   * 释放所有锁,通过请求锁定表解锁每个锁。
   */
  public void release() {
    for (Block blk : locks.keySet())
      locktbl.unlock(blk);
    locks.clear();
  }

  private boolean hasXLock(Block blk) {
    String locktype = locks.get(blk);
    return locktype != null && locktype.equals("X");
  }
}
